﻿#pragma once
#include <dp/config.h>
#include <windows.h>

#include <dp/sys/common.h>
#include <dp/thread/WaitHandle.h>

#include <iostream>

DP_BEGIN

// Hỏi: nếu ta close event khi có thread đang wait thì điều gì xảy ra?
// Hỏi: Nếu là autoreset event (autolock door) việc set (open) sẽ cho phép bao nhiêu thread đi qua trước khi event (cửa) tự đóng lại?

// Lóe: dùng Foo(Obj &o) thay cho Foo(Obj *o) nếu không muốn user viết Foo(new Obj)

// MS: An event object is a synchronization object whose state can be explicitly set to signaled
// by use of the SetEvent function. Following are the two types of event object.
// Manual-reset event:
//		An event object whose state remains signaled until it is explicitly reset to nonsignaled 
//		by the ResetEvent function. While it is signaled, any number of waiting threads, or threads 
//		that subsequently specify the same event object in one of the wait functions, can be released.
// Auto-reset event:
//		An event object whose state remains signaled until a single waiting thread is released, at 
//		which time the system automatically sets the state to nonsignaled. 
//		If no threads are waiting, the event object's state remains signaled. If more than one thread
//		is waiting, a waiting thread is selected. Do not assume a first-in, first-out (FIFO) order. 
//		External events such as kernel-mode APCs can change the wait order.
class DP_DECL Event : public WaitHandle
{
NO_COPY_OR_ASSIGN(Event)

// CONSTRUCTORS
public:
	// The constructor use CreateEvent
	Event(BOOL bManualReset, BOOL bInitialState)
	{
		Handle = CreateEvent(NULL, bManualReset, bInitialState, NULL);
	}

	// The constructor use OpenEvent - REMOVE because of dangerous when lpName donot meet criteria.
	// IDEA: use named constructor
	// Event(LPCTSTR lpName)
	// {
	//	m_handle = OpenEvent(EVENT_ALL_ACCESS, FALSE, lpName);
	// }

// METHODS
public:

	// MS: The ResetEvent function sets the specified event object to the nonsignaled state.
	// MS: EVENT_MODIFY_STATE access right
	// throw Win32Exception
	void Reset()
	{
		BOOL ret;
		ret = ResetEvent(Handle);
		if(!ret)
			throw Win32Exception(__FUNCTION__);
	}

	// MS: The SetEvent function sets the specified event object to the signaled state.
	// throw Win32Exception
	void Set()
	{
		BOOL ret;
		ret = SetEvent(Handle);
		if(!ret)
			throw Win32Exception(__FUNCTION__);
	}

	// MS: Note  This function is unreliable and should not be used. It exists mainly for backward compatibility.
	// MS: EVENT_MODIFY_STATE access right
	// throw Win32Exception
	void Pulse()
	{
		BOOL ret;
		ret = PulseEvent(Handle);
		if(!ret)
			throw Win32Exception(__FUNCTION__);
	}
};

DP_END
